﻿using DeviceDebugger.Common;
using DeviceDebugger.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace DeviceDebugger.DataAccess
{
    public class StackerVisitor
    {
        /// <summary>
        /// 委托，方法参数
        /// </summary>
        public delegate void TroubleFunc(string TroubleText);


        /// <summary>
        /// 全局通用PLC
        /// </summary>
        private S7Client PLC { get; set; }

        private List<TroubleConfigModel> listTroubleCode;

        public StackerVisitor(S7Client plc)
        {
            PLC = plc;
            listTroubleCode = DataVisitor.GetTroubleConfig();
        }

        #region 测试环境模拟堆垛机执行作业时间
        private System.Windows.Threading.DispatcherTimer timer = new();
        private bool bTaskSuccess = false;
        #endregion

        /// <summary>
        /// 堆垛机任务写入PLC
        /// </summary>
        /// <param name="PLC">PLC实例</param>
        /// <param name="TaskModel">任务Model，确保开始位置和目标位置格式为：巷道-排-列-层</param>
        /// <returns></returns>
        public bool SendTask(StackerTasksModel TaskModel, TroubleFunc execeptionFunc)
        {
            ////测试环境结果
            //timer.Interval = TimeSpan.FromSeconds(10);
            //timer.Tick += new EventHandler(ChangedTaskSuccess);
            //timer.Start();
            //bTaskSuccess = false;
            //return true;
            /////////////////////////////////////////////////////////////////

            //判断PLC正确连接
            if (PLC == null || !PLC.Connected())
                return false;

            bool ExecuteResult = false;

            string[] starArray = TaskModel.StartLocation.Split('-');
            string[] endArray = TaskModel.EndLocation.Split('-');
            //空闲状态
            bool isFree = (bool)GetValues(ApplicationStore.DicProtocol["空闲状态"]);
            if (isFree)
            {
                #region 将任务写入PLC中
                //作业校验码，需要计算得出
                int VerifyNumber = 0;

                //作业方式 5是取放作业
                SetValues(ApplicationStore.DicProtocol["作业方式"], 5);
                VerifyNumber += 5;
                ApplicationStore.DicProtocol["作业方式"].Value = 5;

                //起始巷道
                SetValues(ApplicationStore.DicProtocol["起始巷道号"], int.Parse(starArray[0]));
                ApplicationStore.DicProtocol["起始巷道号"].Value = int.Parse(endArray[0]);

                //目的巷道
                SetValues(ApplicationStore.DicProtocol["目的巷道号"], int.Parse(endArray[0]));
                ApplicationStore.DicProtocol["目的巷道号"].Value = int.Parse(endArray[0]);

                //起始站台号
                SetValues(ApplicationStore.DicProtocol["起始站台号"], 0);
                VerifyNumber += 0;
                ApplicationStore.DicProtocol["起始站台号"].Value = 0;

                //目的站台号
                SetValues(ApplicationStore.DicProtocol["目的站台号"], 0);
                VerifyNumber += 0;
                ApplicationStore.DicProtocol["目的站台号"].Value = 0;

                //起始排
                SetValues(ApplicationStore.DicProtocol["起始排"], int.Parse(starArray[1]));
                VerifyNumber += int.Parse(starArray[1]);
                ApplicationStore.DicProtocol["起始排"].Value = int.Parse(starArray[1]);

                //起始列
                SetValues(ApplicationStore.DicProtocol["起始列"], int.Parse(starArray[2]));
                VerifyNumber += int.Parse(starArray[2]);
                ApplicationStore.DicProtocol["起始列"].Value = int.Parse(starArray[2]);

                //起始层
                SetValues(ApplicationStore.DicProtocol["起始层"], int.Parse(starArray[3]));
                VerifyNumber += int.Parse(starArray[3]);
                ApplicationStore.DicProtocol["起始层"].Value = int.Parse(starArray[3]);

                //目的排
                SetValues(ApplicationStore.DicProtocol["目的排"], int.Parse(endArray[1]));
                VerifyNumber += int.Parse(endArray[1]);
                ApplicationStore.DicProtocol["目的排"].Value = int.Parse(endArray[1]);

                //目的列
                SetValues(ApplicationStore.DicProtocol["目的列"], int.Parse(endArray[2]));
                VerifyNumber += int.Parse(endArray[2]);
                ApplicationStore.DicProtocol["目的列"].Value = int.Parse(endArray[2]);

                //目的层
                SetValues(ApplicationStore.DicProtocol["目的层"], int.Parse(endArray[3]));
                VerifyNumber += int.Parse(endArray[3]);
                ApplicationStore.DicProtocol["目的层"].Value = int.Parse(endArray[3]);

                //任务号
                Random r = new Random();

                int taskNumber= r.Next(1000, 9999);
                SetValues(ApplicationStore.DicProtocol["任务号"], taskNumber);
                VerifyNumber += Convert.ToInt32(taskNumber);
                ApplicationStore.DicProtocol["任务号"].Value = taskNumber;


                //下发托盘号
                SetValues(ApplicationStore.DicProtocol["下发托盘号"], 100001);
                ApplicationStore.DicProtocol["下发托盘号"].Value = 100001;

                //作业校验码
                SetValues(ApplicationStore.DicProtocol["作业校验码"], VerifyNumber);
                ApplicationStore.DicProtocol["作业校验码"].Value = VerifyNumber;

                #endregion

                Thread.Sleep(100);

                int VerifyNumber_back = Convert.ToInt32(GetValues(ApplicationStore.DicProtocol["电器校验码"]));
                if (VerifyNumber_back == VerifyNumber)
                {
                    //确认信号
                    SetValues(ApplicationStore.DicProtocol["下发数据确认位"], true);
                    ExecuteResult = true;
                }
                else
                {
                    execeptionFunc.Invoke(String.Format("校验失败，写入校验码：{0}；电器校验码：{1}", VerifyNumber,VerifyNumber_back));
                    ExecuteResult = false;
                }
            }

            return ExecuteResult;
        }

        /// <summary>
        /// 测试环境模拟
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ChangedTaskSuccess(object sender, EventArgs e)
        {
            bTaskSuccess = true;
        }

        /// <summary>
        /// 判断任务完成状态
        /// </summary>
        /// <param name="PLC"></param>
        /// <param name="taskId"></param>
        /// <returns></returns>
        public bool TaskProcss(Int64 taskId)
        {
            //if (bTaskSuccess)
            //{
            //    timer.Stop();
            //}

            //return bTaskSuccess;

            bool bResult = false;

            //判断PLC正确连接
            if (PLC == null || !PLC.Connected())
                return false;

            string taskId_PLC = GetValues(ApplicationStore.DicProtocol["任务号"]).ToString();
            bool isFree = (bool)GetValues(ApplicationStore.DicProtocol["空闲状态"]);
            bool isTrouble= (bool)GetValues(ApplicationStore.DicProtocol["故障"]);
            if (taskId_PLC == 0.ToString() && isFree&&!isTrouble)
                bResult = true;

            return bResult;
        }

        /// <summary>
        /// 读取PLC中点值，并判断是否有故障
        /// </summary>
        /// <param name="TroubleFunc"></param>
        public void ReadPLC(TroubleFunc TroubleFunc)
        {
            if (!(bool)GetValues(ApplicationStore.DicProtocol["通讯状态"]))
            {
                PLC.Disconnect();
                Thread.Sleep(100);
                if (PLC.ConnectTo(ApplicationStore.CurrentStacker.IPAdress, 0, 1) == 1)
                {
                    return;
                }
            }

            var FilterProtocol = ApplicationStore.DicProtocol.Values.Where(a => a.ProtocolType == Model.Enums.ProtocolType.读取 && a.IsDisplay);
            //循环读取所有点的值
            foreach (var item in FilterProtocol)
            {
                ApplicationStore.DicProtocol[item.Name].Value = GetValues(ApplicationStore.DicProtocol[item.Name]);
            }

            //判断故障状态
            if (ApplicationStore.DicProtocol["故障"].IsDisplay && Convert.ToBoolean(ApplicationStore.DicProtocol["故障"].Value))
            {
                //判断故障类型
                if (ApplicationStore.DicProtocol["垂直故障代码"].IsDisplay)
                {
                    int iVerticalTroubleCode = Convert.ToInt32(ApplicationStore.DicProtocol["垂直故障代码"].Value);
                    if (ApplicationStore.CurrentStacker.VerticalTroubleCode != iVerticalTroubleCode)
                    {
                        for (int i = 0; i < 32; i++)
                        {
                            //原来无故障，现在有故障
                            if (!IsTrouble(ApplicationStore.CurrentStacker.VerticalTroubleCode, i) && IsTrouble(iVerticalTroubleCode, i))
                            {
                                string troubleDescription = GetTroubleDes("垂直", i);
                                TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【垂直故障】：" + troubleDescription);
                                ApplicationStore.CurrentStacker.VerticalTroubleCode = iVerticalTroubleCode;
                            }
                        }
                    }
                }
                if (ApplicationStore.DicProtocol["水平故障代码"].IsDisplay)
                {
                    int iLevelTroubleCode = Convert.ToInt32(ApplicationStore.DicProtocol["水平故障代码"].Value);
                    if (ApplicationStore.CurrentStacker.LevelTroubleCode != iLevelTroubleCode)
                    {
                        for (int i = 0; i < 32; i++)
                        {
                            //原来无故障，现在有故障
                            if (!IsTrouble(ApplicationStore.CurrentStacker.LevelTroubleCode, i) && IsTrouble(iLevelTroubleCode, i))
                            {

                                string troubleDescription = GetTroubleDes("水平", i);
                                TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【水平故障】：" + troubleDescription);
                                ApplicationStore.CurrentStacker.LevelTroubleCode = iLevelTroubleCode;
                            }
                        }
                    }
                }
                if (ApplicationStore.DicProtocol["货叉故障代码"].IsDisplay)
                {
                    int iForkTroubleCode = Convert.ToInt32(ApplicationStore.DicProtocol["货叉故障代码"].Value);
                    if (ApplicationStore.CurrentStacker.ForkTroubleCode != iForkTroubleCode)
                    {
                        for (int i = 0; i < 32; i++)
                        {
                            //原来无故障，现在有故障
                            if (!IsTrouble(ApplicationStore.CurrentStacker.ForkTroubleCode, i) && IsTrouble(iForkTroubleCode, i))
                            {
                                string troubleDescription = GetTroubleDes("货叉", i);
                                TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【货叉故障】：" + troubleDescription);
                                ApplicationStore.CurrentStacker.ForkTroubleCode = iForkTroubleCode;
                            }
                        }
                    }
                }
                if (ApplicationStore.DicProtocol["状态故障代码"].IsDisplay)
                {
                    int iStatusTroubleCode = Convert.ToInt32(ApplicationStore.DicProtocol["状态故障代码"].Value);
                    if (ApplicationStore.CurrentStacker.StatusTroubleCode != iStatusTroubleCode)
                    {
                        for (int i = 0; i < 32; i++)
                        {
                            //原来无故障，现在有故障
                            if (!IsTrouble(ApplicationStore.CurrentStacker.StatusTroubleCode, i) && IsTrouble(iStatusTroubleCode, i))
                            {
                                string troubleDescription = GetTroubleDes("系统", i);
                                TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【系统故障】：" + troubleDescription);
                                ApplicationStore.CurrentStacker.StatusTroubleCode = iStatusTroubleCode;
                            }
                        }
                    }
                }
                if (ApplicationStore.DicProtocol["托盘号错"].IsDisplay)
                {
                    bool SalverError = Convert.ToBoolean(ApplicationStore.DicProtocol["托盘号错"].Value);
                    if (!ApplicationStore.CurrentStacker.SalverError && SalverError)
                    {
                        TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【托盘号错】");
                        ApplicationStore.CurrentStacker.SalverError = true;
                    }
                }
                if (ApplicationStore.DicProtocol["取货无箱"].IsDisplay)
                {
                    bool FetchNothing = Convert.ToBoolean(ApplicationStore.DicProtocol["取货无箱"].Value);
                    if (!ApplicationStore.CurrentStacker.FetchNothing && FetchNothing)
                    {
                        TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【取货无箱】");
                        ApplicationStore.CurrentStacker.FetchNothing = true;
                    }
                }
                if (ApplicationStore.DicProtocol["双重入库"].IsDisplay)
                {
                    bool DoubleIn = Convert.ToBoolean(ApplicationStore.DicProtocol["双重入库"].Value);
                    if (!ApplicationStore.CurrentStacker.DoubleIn && DoubleIn)
                    {
                        TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【双重入库】");
                        ApplicationStore.CurrentStacker.DoubleIn = true;
                    }
                }
                //if (ApplicationStore.DicProtocol["取深浅有"].IsDisplay)
                //{
                //    bool FetchNothing2 = Convert.ToBoolean(ApplicationStore.DicProtocol["取深浅有"].Value);
                //    if (!ApplicationStore.CurrentStacker.FetchNothing2 && FetchNothing2)
                //    {
                //        TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【取深浅有】");
                //        ApplicationStore.CurrentStacker.FetchNothing2 = true;
                //    }
                //}
                //if (ApplicationStore.DicProtocol["放深浅有"].IsDisplay)
                //{
                //    bool DoubleIn2 = Convert.ToBoolean(ApplicationStore.DicProtocol["放深浅有"].Value);
                //    if (!ApplicationStore.CurrentStacker.DoubleIn2 && DoubleIn2)
                //    {
                //        TroubleFunc.Invoke(ApplicationStore.CurrentStacker.Name + "发生【放深浅有】");
                //        ApplicationStore.CurrentStacker.DoubleIn2 = true;
                //    }
                //}
            }

        }

        #region 内部方法
        /// <summary>
        /// 获取PLC中点的值
        /// </summary>
        /// <param name="PLC"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        private object GetValues(ProtocolModel model)
        {
            int DBNumber;
            int start;
            int index;
            object oResult = string.Empty;
           if (model.PLC_Adress.Contains(','))
            {
                string[] ssAdress = model.PLC_Adress.Split(',');
                DBNumber = int.Parse(ssAdress[0].Substring(2));

                if (ssAdress[1].Substring(0, 3).ToUpper() == "DBW")
                {
                    start = int.Parse(ssAdress[1].Substring(3));
                    oResult = PLC.GetW(DBNumber, start);
                }
                else if (ssAdress[1].Substring(0, 3).ToUpper() == "DBD")
                {
                    start = int.Parse(ssAdress[1].Substring(3));
                    oResult = PLC.GetDW(DBNumber, start);
                }
                else if (ssAdress[1].Substring(0, 3).ToUpper() == "DBX")
                {
                    if (ssAdress[1].Substring(3).Contains('.'))
                    {
                        var tempArray = ssAdress[1].Substring(3).Split('.');
                        start = int.Parse(tempArray[0]);
                        index = int.Parse(tempArray[1]);
                        oResult = PLC.GetX(DBNumber, start, index);
                    }
                }
            }
            return oResult;
        }

        /// <summary>
        /// 将值写入PLC中的点
        /// </summary>
        /// <param name="PLC"></param>
        /// <param name="model"></param>
        /// <param name="value"></param>
        private void SetValues(ProtocolModel model, object value)
        {
            int DBNumber;
            int start;
            int index;
            if (model.PLC_Adress.Contains(','))
            {
                string[] ssAdress = model.PLC_Adress.Split(',');
                DBNumber = int.Parse(ssAdress[0].Substring(2));

                if (ssAdress[1].Substring(0, 3).ToUpper() == "DBW")
                {
                    start = int.Parse(ssAdress[1].Substring(3));
                    int tempValue;
                    if (int.TryParse(value.ToString(), out tempValue))
                        PLC.SetW(DBNumber, start, tempValue);
                }
                else if (ssAdress[1].Substring(0, 3).ToUpper() == "DBD")
                {
                    start = int.Parse(ssAdress[1].Substring(3));
                    int tempValue;
                    if (int.TryParse(value.ToString(), out tempValue))
                        PLC.SetDW(DBNumber, start, tempValue);
                }
                else if (ssAdress[1].Substring(0, 3).ToUpper() == "DBX")
                {
                    if (ssAdress[1].Substring(3).Contains('.'))
                    {
                        var tempArray = ssAdress[1].Substring(3).Split('.');
                        start = int.Parse(tempArray[0]);
                        index = int.Parse(tempArray[1]);
                        bool tempValue;
                        if (bool.TryParse(value.ToString(), out tempValue))
                            PLC.SetX(DBNumber, start, index, tempValue);
                    }
                }
            }
        }

        /// <summary>
        /// 是否有故障
        /// </summary>
        /// <param name="code"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private bool IsTrouble(int code, int index)
        {
            bool result = false;

            string trouble = Convert.ToString(code, 2);
            trouble = trouble.PadLeft(32, '0');

            if (index >= 0 && index <= 7)
            {
                result = trouble.Substring(7 - index, 1) == "1" ? true : false;
            }
            else if (index >= 8 && index <= 15)
            {
                result = trouble.Substring(15 - index + 8, 1) == "1" ? true : false;
            }
            else if (index >= 16 && index <= 23)
            {
                result = trouble.Substring(23 - index + 16, 1) == "1" ? true : false;
            }
            else if (index >= 24 && index <= 31)
            {
                result = trouble.Substring(31 - index + 24, 1) == "1" ? true : false;
            }
            return result;
        }

        /// <summary>
        /// 获取故障详情
        /// </summary>
        /// <param name="troubleType"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private string GetTroubleDes(string troubleType, int index)
        {
            string result = "";

            switch (troubleType)
            {
                case "垂直":
                    if (index >= 0 && index <= 7)
                    {
                        result = "db_9_8_" + index.ToString();
                    }
                    else if (index >= 8 && index <= 15)
                    {
                        result = "db_9_9_" + (index - 8).ToString();
                    }
                    else if (index >= 16 && index <= 23)
                    {
                        result = "db_9_10_" + (index - 16).ToString();
                    }
                    else if (index >= 24 && index <= 31)
                    {
                        result = "db_9_11_" + (index - 24).ToString();
                    }
                    break;
                case "水平":
                    if (index >= 0 && index <= 7)
                    {
                        result = "db_9_4_" + index.ToString();
                    }
                    else if (index >= 8 && index <= 15)
                    {
                        result = "db_9_5_" + (index - 8).ToString();
                    }
                    else if (index >= 16 && index <= 23)
                    {
                        result = "db_9_6_" + (index - 16).ToString();
                    }
                    else if (index >= 24 && index <= 31)
                    {
                        result = "db_9_7_" + (index - 24).ToString();
                    }
                    break;
                case "货叉":
                    if (index >= 0 && index <= 7)
                    {
                        result = "db_9_12_" + index.ToString();
                    }
                    else if (index >= 8 && index <= 15)
                    {
                        result = "db_9_13_" + (index - 8).ToString();
                    }
                    else if (index >= 16 && index <= 23)
                    {
                        result = "db_9_14_" + (index - 16).ToString();
                    }
                    else if (index >= 24 && index <= 31)
                    {
                        result = "db_9_15_" + (index - 24).ToString();
                    }
                    break;
                case "系统":
                    if (index >= 0 && index <= 7)
                    {
                        result = "db_9_0_" + index.ToString();
                    }
                    else if (index >= 8 && index <= 15)
                    {
                        result = "db_9_1_" + (index - 8).ToString();
                    }
                    else if (index >= 16 && index <= 23)
                    {
                        result = "db_9_2_" + (index - 16).ToString();
                    }
                    else if (index >= 24 && index <= 31)
                    {
                        result = "db_9_3_" + (index - 24).ToString();
                    }
                    break;
            }

            try
            {
                var ent = listTroubleCode.Find(t => t.DeviceType.ToLower() == "stacker" && t.SiteCode == result);
                if (ent != null)
                {
                    return ent.TroubleDescribe;
                }
                else
                {
                    return string.Empty;
                }
            }
            catch
            {
                return "位置错误";
            }
        }

        #endregion
    }
}
